using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

using System.Data;
using System.Data.SqlClient;

using Antix;

namespace Antix.Data.Catalogue.Objects
{
    /// <summary>
    /// Database Column
    /// </summary>
    public class DatabaseColumn : DatabaseObject
    {
        #region Constructor/Defaults

        /// <summary>
        /// Create a new column with defaults
        /// </summary>
        /// <param name="server">Server</param>
        internal DatabaseColumn(DatabaseTable table)
            : this("(new column)", "varchar", 50, true, null, null, table)
        {
            base.IsNew = true;
        }

        /// <summary>
        /// Create an existing column object
        /// </summary>
        internal DatabaseColumn(
            string nameOriginal,
            string typeName, int length, bool allowNull,
            string defaultNameOriginal, string defaultValue,
            DatabaseTable table)
            : base(nameOriginal)
        {
            Table = table;
            _TypeName = typeName;
            _Length = length;
            _AllowNull = allowNull;

            _Default = new DefaultConstraint(defaultNameOriginal, defaultValue);
        }

        #endregion

        #region Properties

        #region Key

        /// <summary>
        /// Key for this object
        /// </summary>
        public override string Key
        {
            get { return this.Name; }
        }

        #endregion

        public DatabaseTable Table{get; private set;}

        #region Type

        private string _TypeName;

        /// <summary>
        /// Column Type
        /// </summary>
        public string TypeName
        {
            get { return _TypeName; }
            set
            {
                if (_TypeName != value)
                {
                    _TypeName = value;
                    base.IsEdited = true;
                }
            }
        }

        /// <summary>
        /// Get the SqlDbType for this colum
        /// </summary>
        public SqlDbType SqlDbType
        {
            get { return DatabaseColumn.GetSqlDbType(this.TypeName); }
        }

        #endregion

        #region Length

        private int _Length;

        /// <summary>
        /// Column Length
        /// </summary>
        public int Length
        {
            get { return _Length; }
            set
            {
                if (_Length != value)
                {
                    _Length = value;
                    base.IsEdited = true;
                }
            }
        }

        #endregion

        #region AllowNull

        private bool _AllowNull;

        /// <summary>
        /// Column Allow Null
        /// </summary>
        public bool AllowNull
        {
            get { return _AllowNull; }
            set
            {
                if (_AllowNull != value)
                {
                    _AllowNull = value;
                    base.IsEdited = true;
                }
            }
        }

        #endregion

        #region Default

        #region Object Class

        /// <summary>
        /// Database Column Default
        /// </summary>
        public class DefaultConstraint
        {
            #region Constructor/Defaults

            /// <summary>
            /// Create an existing column default object
            /// </summary>
            internal DefaultConstraint(
                string nameOriginal, string value)
            {
                this.IsNew = nameOriginal == null;

                _NameOriginal = nameOriginal;
                _Value = value;
            }

            #endregion

            #region Properties

            #region Status

            #region IsNew

            private bool _IsNew;

            /// <summary>
            /// Object is new
            /// </summary>
            public bool IsNew
            {
                get { return _IsNew; }
                set { _IsNew = value; }
            }

            #endregion

            #region IsEdited

            private bool _IsEdited;

            /// <summary>
            /// Object has changed
            /// </summary>
            public bool IsEdited
            {
                get { return _IsEdited; }
                internal set { _IsEdited = value; }
            }

            #endregion

            #endregion

            #region Name

            private string _NameOriginal;

            /// <summary>
            /// Original name
            /// </summary>
            public string NameOriginal
            {
                get { return _NameOriginal; }
            }

            #endregion

            #region Value

            private string _Value;

            /// <summary>
            /// Value value
            /// </summary>
            public string Value
            {
                get { return _Value; }
                set
                {
                    if (!string.Equals(
                        _Value, value, 
                        StringComparison.InvariantCultureIgnoreCase))
                    {
                        _ValueOriginal = _Value;
                        _Value = value;
                        this.IsEdited = true;
                    }
                }
            }

            private string _ValueOriginal;

            public string ValueOriginal
            {
                get { return _ValueOriginal; }
            }

            #endregion

            #endregion

            #region Method

            /// <summary>
            /// Name of the column
            /// </summary>
            public string GetName(DatabaseColumn column)
            {
                return "DF_" + column.Table.Name + "_" + column.Name;
            }

            #endregion
        }

        #endregion

        private DefaultConstraint _Default;

        /// <summary>
        /// Default for this column
        /// </summary>
        public DefaultConstraint Default
        {
            get { return _Default; }
        }

        #endregion

        #endregion

        #region Methods

        #region Script the column

        /// <summary>
        /// Generate script for this column
        /// </summary>
        /// <param name="sql">Sql</param>
        public override bool Script(StringBuilder sql, bool subObjects)
        {
            return this.Table.Database.Script(this, sql, subObjects);
        }

        #endregion

        #region GetIndexes

        /// <summary>
        /// <para>Get indexes this column is in</para>
        /// </summary>
        /// <returns></returns>
        public DatabaseIndex[] GetIndexes()
        {
            ArrayList indexes = new ArrayList();
            string pattern = string.Format(@"^(\[{0}\]|{0})$|^(\[{0}\]|{0})[, ]|,(\[{0}\]|{0})$", Name); ;
            foreach (DatabaseIndex index in Table.Indexes)
            {
                if(Regex.IsMatch(index.Columns, pattern)){ indexes.Add(index); }
            }

            return (DatabaseIndex[])indexes.ToArray(typeof(DatabaseIndex));
        }

        #endregion

        #region GetSqlDbType

        /// <summary>
        /// Get the sqlDbType 
        /// </summary>
        public static SqlDbType GetSqlDbType(string typeName)
        {
            if (Enum.IsDefined(typeof(SqlDbType), typeName))
            {
                return (SqlDbType)Enum.Parse(typeof(SqlDbType), typeName, true);
            }
            else { return SqlDbType.VarChar; }
        }

        #endregion

        #endregion
    }
}